/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package controller;

import controller.algorithme.Algorithme;
import exception.*;
import java.io.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Timer;
import java.util.logging.Level;
import java.util.logging.Logger;
import model.*;

/**
 *
 * @author benoit
 */
public class SimulationControleur {
    private Simulation simulation;
    private AlgorithmeControleur algorithmeControleur;
    private Timer timerService=null;
    String cheminFichierSimulation=null;
    Integer algo=Algorithme.MODE_AUTOMATIQUE;
    private boolean simuEnCours = false;

    public SimulationControleur(Simulation simulation, AlgorithmeControleur algorithmeControleur) {
        this.simulation = simulation;
        this.algorithmeControleur = algorithmeControleur;
    }

    public void setAlgo(Integer algo) {
        this.algo = algo;
    }

    public void setCheminFichierSimulation(String cheminFichierSimulation) {
        this.cheminFichierSimulation = cheminFichierSimulation;
    }
    
    public List<AppelAscenseur> getCurrentAppelAscenseur() {
        return this.simulation.getAppelsAscenseur().get(simulation.getDate().toString());
    }
    
    public void chargerFichierSimulation(String  fichierSimulation, int algo) throws ImpossibleChargerFichierSimulationException {
        BufferedReader fichier_csv;
        int nbrPersonne;
        String chaine;
        String[] tabChaine;
        String[] tabDateProvisoire;
        Date heureAppel;
        int[] tabDate = new int[3];
        Etage etageDepart, etageArrive;
        
        try {        
            fichier_csv = new BufferedReader(new FileReader(fichierSimulation));
            
            while((chaine = fichier_csv.readLine())!= null)
            {
                tabChaine = chaine.split(";");

                etageDepart = simulation.getBatiment().getEtage(Integer.valueOf(tabChaine[1]));
                etageArrive = simulation.getBatiment().getEtage(Integer.valueOf(tabChaine[2]));
                nbrPersonne = Integer.parseInt(tabChaine[3]);
                //System.out.println("Etage départ "+ etageDepart.numero);
                //System.out.println("Etage arrivé "+ etageArrive.numero);
                //System.out.println("Nombre de personne "+nbrPersonne);

                tabDateProvisoire = tabChaine[0].split(":");
                tabDate[0] = Integer.valueOf(tabDateProvisoire[0]);
                tabDate[1] = Integer.valueOf(tabDateProvisoire[1]);
                tabDate[2] = Integer.valueOf(tabDateProvisoire[2]);
                heureAppel = new Date(tabDate[0], tabDate[1], tabDate[2]);
                
                //System.out.println("Heure "+tabDate[0]+" Min "+tabDate[1]+" Seconde "+tabDate[2]+"\n\n");
                simulation.ajouterAppelAscenseur(heureAppel.toString(), new AppelAscenseur(etageDepart, etageArrive, heureAppel, nbrPersonne, AppelAscenseur.UTILISATEUR, algo));
            }
            fichier_csv.close();					
        } catch (IOException | NumberFormatException ex) {
            Logger.getLogger(Simulation.class.getName()).log(Level.SEVERE, null, ex);
            throw new ImpossibleChargerFichierSimulationException();
        }
    }
    
    public void ajouterAppelManuelAscenseur(Ascenseur as,Etage etageDepart,Etage etageArrive,Date heureDemande, Integer algo) throws AppelManuelInvalideException {
        if(as==null || etageDepart == null || etageArrive == null || heureDemande == null || algo == null) {
            throw new AppelManuelInvalideException("Renseigner toutes les informations !");
        }
        heureDemande.incrementer();
        as.getTrajetsEnAttente().add(new Trajet(new AppelAscenseur(etageDepart, etageArrive, heureDemande, 0, Simulation.SUPERVISION, algo), as.getNumero(), as.getEtageCourant()));
    }
    
    public void demarrer(AscenseurControleur ascenseurControleur,long period) throws PasDeFiChierSimulationException, FichierSimulationNonExistantException, ImpossibleChargerFichierSimulationException {
        if(cheminFichierSimulation==null) {
            throw new PasDeFiChierSimulationException();
        }

        File f = new File(cheminFichierSimulation);
        List<AppelAscenseur> appelsAscenseur = new ArrayList<AppelAscenseur>();
        
        if(!f.getAbsoluteFile().isFile()) {
            throw new FichierSimulationNonExistantException();
        }
        
        // TODO : Vérifier le format du fichier de simulation avant de lancer la simulation
        chargerFichierSimulation(cheminFichierSimulation, algo);
        System.out.println(simulation);
        timerService = new Timer("Tache Simulation");
        if(period==0){period=1;}
        timerService.scheduleAtFixedRate(new TacheSimulation(this,ascenseurControleur, algorithmeControleur), 0L, period);
        simuEnCours = true;
    }
    
    public int getHeure() {
        return simulation.getDate().getHeure();
    }
    
    public int getMinute() {
        return simulation.getDate().getMinute();
    }
    
    public int getSeconde() {
        return simulation.getDate().getSeconde();
    }
    
    public void arreter() {
        simuEnCours = false;
        if(timerService != null) {
            timerService.cancel();
        }
    }
    
    public boolean incrementerDate() {
        return simulation.getDate().incrementer();
    }
    
    public void controleFichierSimulation(BufferedReader  fichier_csv) throws FormatFichierSimulationNonConformeException, IOException
    {
        String chaine;
        String heureLignePrec = null;
        String[] tabChaine;
        List<String> tabErreur = null;
        int indexTableau = 0, indexFichier = 1;
            
        while((chaine = fichier_csv.readLine())!= null)
        {
            tabChaine = chaine.split(";");

            //Vérification de l'heure
            if((heureLignePrec.compareTo("") == 0) || (heureLignePrec.compareTo(tabChaine[0]) < 0))
            {
                if(tabChaine[0].compareTo("00:00:00") < 0)
                {
                    //Exception heure inférieure à 00:00:00
                    tabErreur.add("Erreur l."+indexFichier+" : Heure inférieur à 00:00:00\n");
                    indexTableau++;
                }
                else if(tabChaine[0].compareTo("23:59:59") > 0)
                {
                    //Exception heure supérieure à 23:59:59
                    tabErreur.add("Erreur l."+indexFichier+" : Heure supérieure à 23:59:59\n");
                    indexTableau++;
                }
                else
                {
                    heureLignePrec = tabChaine[0];
                }
            }
            else
            {
                //Exception heure inférieure à la précedente
                tabErreur.add("Erreur l."+indexFichier+" : Heure inférieur à la précédente\n");
                indexTableau++;
            }

            //Controle des étages
            if((tabChaine[1].compareTo("39") > 0) || (tabChaine[1].compareTo("-4") < 0) || (tabChaine[1].compareTo(tabChaine[2]) == 0))
            {
                //Exception Mauvais étage départ
                tabErreur.add("Erreur l."+indexFichier+" : Mauvais étage de départ\n");
                indexTableau++;

            }
            else if((tabChaine[2].compareTo("40") > 0) || (tabChaine[1].compareTo("-3") < 0))
            {
                //Exception Mauvais étage arrivé
                tabErreur.add("Erreur l."+indexFichier+" : Mauvais étage d'arrivé\n");
                indexTableau++;
            }

            //Contrôle du nombre de passager
            if((tabChaine[3].compareTo("1") < 0) || (tabChaine[3].compareTo("15") > 0))
            {
                //Exception nombre de personne
                tabErreur.add("Erreur l."+indexFichier+" : Mauvais nombre de passager\n");
                indexTableau++;
            }

            indexFichier++;
        }
        
        if(tabErreur.isEmpty())
        {
            Logger.getLogger(Simulation.class.getName()).log(Level.SEVERE, null, tabErreur);
            throw new FormatFichierSimulationNonConformeException();
        }
    }
    
    public Batiment getBatiment() {
        return this.simulation.getBatiment();
    }
    
    public boolean isSimuEnCours() {
        return simuEnCours;
    }
    
    public void reinitialiser(){
        for(Ascenseur as : this.getBatiment().getAscenseurs().values()) {
            as.getTrajets().clear();
            as.getTrajetsEnAttente().clear();
            as.getTrajetsEnCours().clear();
            
            as.decrementerNbPersonne(as.getNombrePersonne());
            as.setPorteOuverte(false);
            as.setDirectionActuel(Ascenseur.IMMOBILE);
            as.setEtageCourant(as.getEtageInitial());
            as.setStatut(Ascenseur.ST_EN_ATTENTE);
            as.setSurLeDepart(false);
            as.setVitesse(Ascenseur.VITESSE_0);
        }
        
        simulation.getAppelsAscenseur().clear();
        simulation.getDate().reset();
    }
}
